/**
 * @file DataPool.h
 * @author Lost
 * @date 六月 2018
 * @brief 
 * 数据池
 */

#ifndef __DATAPOOL_H__
#define __DATAPOOL_H__

#include <queue>
#include <stdio.h>
#include <string.h>

/*!< 初始化默认块数 */
#define INIT_COUNT 16

/*!< 空间扩展函数 */
#define EXTEND_FUNCTION(cur_count) (cur_count + 2)

/**
 * @brief 数据头
 */
typedef struct stDataHead
{
    /*!< 校验大小 */
    int iCheckSize;

    /*!< 前一个数据 */
    struct stDataHead *pNext;

    /*!< 后一个数据 */
    struct stDataHead *pPrev;
}SDataHead;

/**
 * @brief 数据池
 */
template <int SIZE>
class CDataPool
{
public:
    CDataPool()
        :m_pFreeHead(NULL), m_iUseCount(0), m_iLeftCount(0)
    {
        if (SIZE <= 0)
        {
            return;
        }

        if (INIT_COUNT > Create(INIT_COUNT))
        {
            ReleaseAll();
            return;
        }

        m_iLeftCount = INIT_COUNT;
    }

    ~CDataPool()
    {
        ReleaseAll();
    }
public:
    /**
     * @brief 创建空闲空间
     */
    char * Create()
    {
        if (m_iLeftCount <= 1)
        {
            int iTotalCount = m_iLeftCount + m_iUseCount;
            int iCreateCount = Create(EXTEND_FUNCTION(iTotalCount));
            if (iCreateCount <= 1)
            {
                return NULL;
            }
        }

        if (m_pFreeHead == NULL || m_pFreeHead->pPrev == NULL)
        {
            return NULL;
        }

        SDataHead *pCreateData = m_pFreeHead;
        m_pFreeHead = m_pFreeHead->pNext;

        m_pFreeHead->pPrev = pCreateData->pPrev;
        pCreateData->pPrev->pNext = m_pFreeHead;

        ++m_iUseCount;
        --m_iLeftCount;
        return ((char *)pCreateData)+sizeof(int);
    }

    /**
     * @brief 释放数据空间
     */
    void Release(char *pFree)
    {
        if (pFree == NULL)
        {
            return;
        }

        SDataHead *pFreeData = (SDataHead *) (pFree - sizeof(int));

        if (pFreeData == NULL || pFreeData->iCheckSize != SIZE )
        {
            return;
        }

        if (m_pFreeHead == NULL)
        {
            m_pFreeHead = pFreeData;
            m_pFreeHead->pNext = m_pFreeHead;
            m_pFreeHead->pPrev = m_pFreeHead;
        }
        else
        {
            if (m_pFreeHead->pPrev == NULL)
            {
                return;
            }

            m_pFreeHead->pPrev->pNext = pFreeData;
            pFreeData->pPrev = m_pFreeHead->pPrev;

            pFreeData->pNext = m_pFreeHead;
            m_pFreeHead->pPrev = pFreeData;
        }

        ++m_iLeftCount;
        --m_iUseCount;
    }

    /**
     * @brief 调试输出
     */
    const char * PrintString()
    {
        static char csPrintString[64];

        int iFreeCount = 0;
        SDataHead *pTemp = m_pFreeHead;
        while (pTemp != NULL)
        {
            ++iFreeCount;
            pTemp = pTemp->pNext;
            if (pTemp == m_pFreeHead)
            {
                break;
            }
        }

        snprintf(csPrintString, sizeof(csPrintString), 
            "Size:%d Left:%d Use:%d Total:%d Free:%d",SIZE, m_iLeftCount, m_iUseCount, m_iLeftCount+m_iUseCount, iFreeCount);

        return csPrintString;
    }
private:
    /**
     * @brief 删除所有空间
     */
    void ReleaseAll()
    {
        if (m_pFreeHead != NULL)
        {
            if (m_pFreeHead->pPrev == NULL || m_pFreeHead->pNext == NULL)
            {
                return;
            }
            SDataHead *pTmp = m_pFreeHead->pPrev;
            char *pDelete = NULL;
            if (pTmp != m_pFreeHead)
            {
                pTmp = pTmp->pNext;

                pDelete = (char*)pTmp->pPrev;
                delete[]pDelete;
                pTmp = NULL;
            }
            pDelete = (char*)m_pFreeHead;
            delete[]pDelete;
            m_pFreeHead = NULL;
            pDelete = NULL;
        }
        m_iUseCount = 0;
        m_iLeftCount = 0;
    }
    
    /**
     * @brief 创建Count个数据空间
     */
    int Create(int iCount)
    {
        if (SIZE <= 0)
        {
            return 0;
        }

        int iCreateCount = 0;
        for (int iTmpCount = 0; iTmpCount < iCount; ++iTmpCount)
        {
            char *pNewFree = new char[SIZE + sizeof(int)];
            if (pNewFree == NULL)
            {
                break;
            }
            memset(pNewFree, 0, SIZE);

            stDataHead *pTmpHead = (stDataHead *)pNewFree;

            pTmpHead->iCheckSize = SIZE;

            if (m_pFreeHead == NULL)
            {
                if (pTmpHead == NULL)
                {
                    break;
                }
                m_pFreeHead = pTmpHead;
                pTmpHead->pPrev = pTmpHead;
                pTmpHead->pNext = pTmpHead;
            }
            else
            {
                if (pTmpHead == NULL || m_pFreeHead->pPrev == NULL )
                {
                    break;
                }
                m_pFreeHead->pPrev->pNext = pTmpHead;
                pTmpHead->pNext = m_pFreeHead;

                pTmpHead->pPrev = m_pFreeHead->pPrev->pPrev;
                m_pFreeHead->pPrev = pTmpHead;
            }
            ++iCreateCount;
        }

        m_iLeftCount += iCreateCount;

        return iCreateCount;
    }

private:
    /*!< 使用数量 */
    int m_iUseCount;

    /*!< 剩余数量 */
    int m_iLeftCount;

    /*!< 空闲空间链表头 */
    SDataHead *m_pFreeHead;

};

#endif // __DATAPOOL_H__
